﻿#define _CRT_SECURE_NO_WARNINGS
// ↑ 将本行在代码放在第一行可以避免 scanf的报错问题（仅在VS编译器里）
//【初阶】26.多态(2)

//【头文件包含】
//C++的主要头文件
#include<iostream>//c++的输入输出流
using namespace std;
#include"string.h"
//using std::cout, std::endl, std::cin;
#include<vector>
#include<list>
//C的主要头文件
//#include<stdio.h>
//#include<stdlib.h>
//#include<assert.h>
//#include<string.h> 

//ABCAB


//【命名空间】

//【结构体声明】【类声明】
//单继承虚表
class Base
{
public:
	virtual void Func1()
	{
		cout << "Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Func2()" << endl;
	}
	void Func3()
	{
		cout << "Base::Func3()" << endl;
	}
private:
	int _b = 1;
};
// 针对上面的代码我们做出以下改造
// 1.我们增加一个派生类Derive去继承Base
// 2.Derive中重写Func1
// 3.Base再增加一个虚函数Func2和一个普通函数Func3
class Derive : public Base
{
public:
	virtual void Func1()
	{
		cout << "Derive::Func1()" << endl;
	}
	virtual void Func4()
	{
		cout << "Func4()" << endl;
	}
	virtual void Func5()
	{
		cout << "Func4()" << endl;
	}
private:
	int _d = 2;
};

//多态原理
class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
	int _P = 1;
};
class Student : public Person {
public:
	virtual void BuyTicket() { cout << "买票-半价" << endl; }
	int _S = 2;
};
void Func(Person& p)
{
	p.BuyTicket();
}
void Func_(Person* pp)
{
	pp->BuyTicket();
}
void Func__(Person p)
{
	p.BuyTicket();
}

//多继承虚表
class Base1 {
public:
	virtual void func1() { cout << "Base1::func1" << endl; }
	virtual void func2() { cout << "Base1::func2" << endl; }
private:
	int b1;
};
class Base2 {
public:
	virtual void func1() { cout << "Base2::func1" << endl; }
	virtual void func2() { cout << "Base2::func2" << endl; }
private:
	int b2;
};
class Derive12 :  public Base1,public Base2 {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
private:
	int d1;
};



//【函数声明】
void Test1();void Test2();void Test3();


//【主函数】
int main()
{
	
	Test1();
	Test2();
	Test3();
	
	cout << "****主函数结束****" << endl;
	return 0;
}

//【函数定义】


/*测试用例*/void Test1()
{

	cout << "****测试用例开始****"<< endl;
	//虚函数表
	Base b;
	Base b2;
	Derive d;
	Derive d2;
	cout << sizeof(Base) << endl;//包括1个虚函数表指针和1个int成员x64:8+4+04
	cout << sizeof(Derive) << endl;//包括1个虚函数表指针和2个int成员x64:8+4+04+4+04
	//多态原理
	Person Mike;
	Func(Mike);
	Func_(&Mike);
	Func__(Mike);
	Student Johnson;
	Func(Johnson);
	Func_(&Johnson);
	Func__(Johnson);
	cout << sizeof(Person) << endl;//x64:16
	cout << sizeof(Student) << endl;//x64:24

	cout << "****测试用例结束****" << endl << endl;

}

/*测试用例*/void Test2()
{
	cout << "****测试用例开始****" << endl;
	

	cout << "****测试用例结束****" << endl<<endl;
}

/*测试用例*/void Test3()
{
	cout << "****测试用例开始****" << endl;
	Derive12 d;
	cout << sizeof(Base1) << endl;//x64:16
	cout << sizeof(Base2) << endl;//x64:16
	cout << sizeof(Derive12) << endl;//x64:16+16+4+04



	cout << "****测试用例结束****" << endl << endl;
}

//【笔记】
//【初阶】26.多态(2)
	//内敛函数不能是虚函数	
	//抽象类
		// 纯虚函数：在虚函数后面写上=0，包含纯虚函数的类叫做抽象类也叫接口类
		// 派生类继承后如果不重写纯虚函数（既要重写，还要定义（不能只声明）），则不能实例化出对象
		// 普通函数继承时实现继承、虚函数集成是接口继承，如果不实现多态则不要写成虚函数 
	//多态原理
		//虚函数表:（虚表）（指针数组）
			// 虚表存放在代码段中
			// 一个含有虚函数的类中都至少都有一个虚函数表指针，因为虚函数的地址要被放到虚函数表中
			// 而虚函数表中可以存放多个虚函数的地址
			// 虚函数表的结尾会有一个nullptr作为结束判断
			
		//原理：（虚函数、重写、使用指针或者引用调用虚函数）
			// 满足多态以后的函数调用，不是在编译时确定的，是运行起来以后到对象的中取找的。
			// 不满足多态的函数调用是编译时确认好的。
		//静态绑定
			// 早绑定，在程序编译期间确定程序的行为，如：函数重载
		//动态绑定
			// 晚绑定，在程序运行期间根据拿到的类型确定程序行为，调用具体函数，如类中的多态实现
		//以上说明
			// 我也认多态的状态是否实现在编译时已经确认了，只是满足多态调用的检查是在运行时去判断的
			// 有些时候即便有虚函数但不构成重写编译时也能通过，运行时不构成多态
			// 所以最好利用override做好重写检查
		//单继承的虚表
			// 用同一个类生成的对象共用同一个虚表
			// 而基类和派生类不是同一个类（更正上节课的误解） 两者生成的对象会有两个不同的虚表
		//多继承的虚表
			// 多继承派生类的未重写的虚函数放在第一个继承基类部分的虚函数表中
		//虚基表和虚表不是同一个东西
			// 虚基表是存储偏移量的是解决菱形继承二义性的




